<?php
/**
 * This file defines the PHP class {@see \BF\ExplicitGetterSetter}.
 *
 * @author   Kado <ulfikado@gmail.com>
 * @category Beluga PHP5.3+ Framework
 * @package  BF\Core
 * @since    2015-01-17 14:54
 * @version  0.1  
 */

namespace BF
{

   require_once __DIR__ . '/ExplicitGetter.class.php';

   /**
    * If you extend youre class from this class, youre class becomes a automatic working magic get + set method for
    * read + write accessing the values of all avialable getXyz + setXyz methods by dynamic properties.
    *
    * For example: If youre class defines the two public get methods 'getFoo()' and 'getFooBar()' and the public
    * set method 'setFooBar( $value ) you can also access it with the dynamic properties
    * $instance->foo [is readonly] and $instance->fooBar [read + write].
    *
    * But dont forget to document youre dyn. class properties with the @ property annotation
    *
    * @since 0.1
    */
   class ExplicitGetterSetter extends \BF\ExplicitGetter
   {

      /**
       * The magic set method to let you access all setter methods by dynamic properties.
       *
       * @param  string $name    The name of the dynamic property.
       * @param  mixed  $value   The value to set.
       * @throws \LogicException Is thrown if the property does not exist or if writing is requested but not allowed.
       */
      public function __set( $name, $value )
      {

         $setterName = null;

         // Trigger a exception if the method not exists
         if ( ! $this->hasWritableProperty( $name, $setterName ) )
         {
            throw new \LogicException( "Property '$name' has no write access!" );
         }

         // Call the method by the dynamic way
         // Originally the setters can also return a success state, but it can not be handled by the
         // magic __set method and will be ignored.
         $this->$setterName( $value );

      }

      /**
       * Magic isset implementation.
       *
       * @param  string $name The name of the required property.
       * @return boolean
       */
      public function __isset( $name )
      {
         if ( \method_exists( $this, 'set' . \ucfirst( $name ) ) )
         {
            return true;
         }
         return parent::__isset( $name );
      }

      /**
       * Returns, if a property with the defined name exists for write access.
       *
       * @param  string $name       The name of the property.
       * @param  string $setterName Returns the name of the associated set method, if method returns TRUE.
       * @return boolean
       */
      public function hasWritableProperty( $name, &$setterName )
      {
         $setterName = 'set' . \ucfirst( $name );
         return \method_exists( $this, $setterName );
      }

   }

}

 